package com.gxd.business.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxd.business.constant.CommonConstants;
import com.gxd.business.constant.DictConstants;
import com.gxd.business.domain.AllocationCustomerLog;
import com.gxd.business.domain.Customer;
import com.gxd.business.domain.dto.TransferCustomerDto;
import com.gxd.business.domain.qco.CustomerQco;
import com.gxd.business.enums.*;
import com.gxd.business.mapper.CustomerMapper;
import com.gxd.business.service.AllocationCustomerLogService;
import com.gxd.business.service.CustomerService;
import com.gxd.business.utils.SysConfigUtil;
import com.gxd.business.websocket.WebSocketServer;
import com.gxd.business.websocket.constant.WebsocketConst;
import com.gxd.common.core.domain.entity.SysUser;
import com.gxd.common.exception.ServiceException;
import com.gxd.common.utils.SecurityUtils;
import com.gxd.common.utils.bean.BeanUtils;
import com.gxd.system.service.ISysDictDataService;
import com.gxd.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author gxd
 * @since 2025/6/13
 */
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService {

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private ISysDictDataService dictDataService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private AllocationCustomerLogService allocationCustomerLogService;

    @Autowired
    private WebSocketServer socketServer;

    /**
     * 分页列表-资源客户列表
     * @param customerQco 资源客户查询条件
     * @return 资源客户列表
     */
    @Override
    public List<Customer> pageList(CustomerQco customerQco) {
        // 资源客户管理：只有管理员能看见，管理员角色查询全部数据；我的客户管理：分配给我并且添加联系方式 | 管理员；公共客户资源：所有未分配的

        String intentionCategory = customerQco.getIntentionCategory();
        if (StrUtil.isNotBlank(intentionCategory)) {
            List<Integer> intentionCategoryList = Arrays.stream(intentionCategory.split(StrPool.COMMA))
                    .map(Integer::parseInt).collect(Collectors.toList());
            customerQco.setIntentionCategoryList(intentionCategoryList);
        }

        // 获取当前登录用户
        Long userId = SecurityUtils.getUserId();
        // 判断是否是管理员
        boolean isAdmin = SysUser.isAdmin(userId);

        Page<Customer> customerPage = new Page<>();
        // 判断访问来源
        if (ObjUtil.equals(ReferrerEnum.PUBLICCUSTOMER.getCode(), customerQco.getReferrer()) || (ObjUtil.equals(ReferrerEnum.CUSTOMER.getCode(), customerQco.getReferrer()) && isAdmin)) {
            if (ObjUtil.equals(ReferrerEnum.PUBLICCUSTOMER.getCode(), customerQco.getReferrer())) {
                // 公共客户资源：未分配状态 并且 未添加联系方式状态
                customerQco.setAssignStatus(AssignStatusEnum.UNASSIGN.getCode());
            }
            // 查询资源客户分页
            customerPage = customerMapper.pageList(new Page<>(customerQco.getPageNum(), customerQco.getPageSize()), customerQco);
        } else if (ObjUtil.equals(ReferrerEnum.MYCUSTOMER.getCode(), customerQco.getReferrer())) {
            // 我的客户管理：分配给我、已分配状态
            if (!isAdmin) {
                // 不是管理员，查询自己管理的客户
                customerQco.setUserId(userId);
            }
            customerQco.setAssignStatus(AssignStatusEnum.ASSIGNED.getCode());
            customerPage = customerMapper.myPageList(new Page<>(customerQco.getPageNum(), customerQco.getPageSize()), customerQco);
        }
      /*  // 对资源客户数据进行翻译
        List<Customer> customers = this.refreshInfo(customerPage.getRecords());*/
        List<Customer> customers = ObjUtil.isEmpty(customerPage.getRecords()) ? Collections.emptyList() : customerPage.getRecords();
        return customers;
    }

/*    *//**
     * 格式化数据：翻译
     * @param customers 资源客户集合
     * @return 资源客户集合
     *//*
    private List<Customer> refreshInfo(List<Customer> customers) {
        // 数据为空，返回空集合
        if (ObjUtil.isEmpty(customers)) return Collections.emptyList();
        // 获取字典Map.从缓存获取，缓存没有再从数据库查询，存入缓存
        Map<String, String> sexMap = dictDataService.getDictValueLabelMap(DictConstants.SYS_USER_SEX);
        Map<String, String> customerSourceMap = dictDataService.getDictValueLabelMap(DictConstants.CUSTOMER_SOURCE);
        Map<String, String> assignStatusMap = dictDataService.getDictValueLabelMap(DictConstants.ASSIGN_STATUS);
        Map<String, String> intentionCategoryMap = dictDataService.getDictValueLabelMap(DictConstants.INTENTION_CATEGORY);
        Map<String, String> intentionLevelMap = dictDataService.getDictValueLabelMap(DictConstants.INTENTION_LEVEL);
        Map<String, String> contactStatusMap = dictDataService.getDictValueLabelMap(DictConstants.CONTACT_STATUS);
        // 对翻译字段进行翻译
        return customers.stream()
                .map(customer -> {
                    customer.setSexMc(sexMap.get(String.valueOf(customer.getSex())));
                    customer.setCustomerSourceMc(customerSourceMap.get(String.valueOf(customer.getCustomerSource())));
                    customer.setAssignStatusMc(assignStatusMap.get(String.valueOf(customer.getAssignStatus())));
                    String intentionCategory = customer.getIntentionCategory();
                    if (StrUtil.isBlank(intentionCategory)) {
                        customer.setIntentionCategory(null);
                    } else {
                        customer.setIntentionCategoryMc(Arrays.stream(intentionCategory.split(StrPool.COMMA))
                                .map(intentionCategoryMap::get)
                                .collect(Collectors.joining(StrPool.COMMA)));
                    }
                    customer.setIntentionLevelMc(intentionLevelMap.get(String.valueOf(customer.getIntentionLevel())));
                    customer.setContactStatusMc(contactStatusMap.get(String.valueOf(customer.getContactStatus())));
                    return customer;
                }).collect(Collectors.toList());
    }*/


    /**
     * 详情信息-根据Id获取资源客户详情信息
     * @param id 资源客户Id
     * @return 资源客户
     */
    @Override
    public Customer getDetailById(String id) {
        // 根据id获取资源客户数据
        Customer customer = this.getById(id);
        // 资源客户数据不为空，进行字段翻译
        if (ObjUtil.isNotNull(customer)) {
            // return refreshInfo(Arrays.asList(customer)).get(0);
            return customer;
        }
        return Customer.builder().build();
    }

    /**
     * 添加或修改-资源客户
     * @param customer 资源实体
     * @return 资源客户
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Customer addOrEdit(Customer customer) {
        // 校验参数
        Assert.notNull(customer, "资源客户不能为空");
        // id不为空，修改
        if (ObjUtil.isNotNull(customer.getId())) {
            // 根据id获取资源客户数据，校验非空
            Customer customerInfo = Assert.notNull(this.getById(customer.getId()), "要修改的资源客户记录不存在");
            // 拷贝数据
            BeanUtils.copyNotEmptyProperties(customer, customerInfo);
            // 更新数据
            this.updateById(customerInfo);
            return customerInfo;
        }
        // 赋值
        customer.setGUID();
        customer.setDeleted(DeletedEnum.NO.getCode());
        // 新增
        this.save(customer);
        return customer;
    }

    /**
     * 删除-资源客户（支持批量）
     * @param ids 资源客户Id（多个需要逗号分隔）
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteById(String ids) {
        // 校验参数
        Assert.notEmpty(ids, "缺少必要参数：请提供要删除的记录Id");
        // 进行逻辑删除
        return this.update(Wrappers.lambdaUpdate(Customer.class)
                .set(Customer::getDeleted, DeletedEnum.YES.getCode()).in(Customer::getId, ids.split(StrPool.COMMA)));
    }

    /**
     * 自动分配
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean automaticAssign() {
        // 查询未分配的资源客户
        List<Customer> customers = this.list(Wrappers.lambdaQuery(Customer.class)
                .eq(Customer::getDeleted, DeletedEnum.NO.getCode()).eq(Customer::getAssignStatus, AssignStatusEnum.UNASSIGN.getCode()));
        if (ObjUtil.isEmpty(customers)) {
            throw new ServiceException("无未分配的资源客户数据！");
        }
        // 查询用户并且角色是工作人员
        String roleKey = SysConfigUtil.getConfigValue(CommonConstants.WORK_PERSONNEL_ROLE_KEY);
        if (StrUtil.isBlank(roleKey)) {
            throw new ServiceException("无用户可以分配！");
        }
        String[] roleKeyArr = roleKey.split(StrPool.COMMA);
        List<SysUser> userList = userService.selectUserListByRoleKey(roleKeyArr);
        if (ObjUtil.isEmpty(userList)) {
            throw new ServiceException("无用户可以分配！");
        }

        // 轮询给资源客户分配用户
        List<AllocationCustomerLog> allocationCustomerLogs = new ArrayList<>();
        int index = 0;
        for (Customer customer : customers) {
            SysUser user = userList.get(index);
            AllocationCustomerLog allocationCustomerLog = new AllocationCustomerLog();
            allocationCustomerLog.setGUID();
            allocationCustomerLog.setCustomerId(customer.getId());
            allocationCustomerLog.setToUserId(user.getUserId());
            allocationCustomerLog.setAssignTime(new Date());
            allocationCustomerLog.setType(AssignTypeEnum.ASSIGN.getCode());
            allocationCustomerLogs.add(allocationCustomerLog);

            index = (index + 1) % userList.size();
        }
        allocationCustomerLogService.saveBatch(allocationCustomerLogs);

        // 更新资源客户状态为已分配
        List<String> ids = customers.stream().map(Customer::getId).collect(Collectors.toList());
        return this.update(Wrappers.lambdaUpdate(Customer.class).set(Customer::getAssignStatus, AssignStatusEnum.ASSIGNED.getCode()).in(Customer::getId, ids));
    }

    /**
     * 导入-资源客户
     * @param file 文件
     * @return 解雇
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean importData(MultipartFile file) {
        try {
            // 字段映射
            Map<String, String> headerAlias = new HashMap<>();
            headerAlias.put("客户名称", "customerName");
            headerAlias.put("联系电话", "phone");
            headerAlias.put("性别", "sexMc");
            headerAlias.put("所属区域", "region");
            headerAlias.put("客户来源", "customerSourceMc");
            headerAlias.put("分配状态", "assignStatusMc");
            headerAlias.put("创建时间", "createTime");
            // 使用hutool读取excel内容，批量插入数据
            ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
            reader.setHeaderAlias(headerAlias);
            List<Customer> customers = reader.readAll(Customer.class);
            // 获取字典Map.从缓存获取，缓存没有再从数据库查询，存入缓存
            Map<String, String> sexMap = dictDataService.getDictLabelValueMap(DictConstants.SYS_USER_SEX);
            Map<String, String> customerSourceMap = dictDataService.getDictLabelValueMap(DictConstants.CUSTOMER_SOURCE);
            Map<String, String> assignStatusMap = dictDataService.getDictLabelValueMap(DictConstants.ASSIGN_STATUS);
            // 数据赋值
            List<Customer> customerList = customers.stream()
                    .map(customer -> {
                        customer.setGUID();
                        customer.setSex(Integer.valueOf(sexMap.get(customer.getSexMc())));
                        customer.setCustomerSource(Integer.valueOf(customerSourceMap.get(customer.getCustomerSourceMc())));
                        customer.setAssignStatus(Integer.valueOf(assignStatusMap.get(customer.getAssignStatusMc())));
                        customer.setDeleted(DeletedEnum.NO.getCode());
                        return customer;
                    })
                    .collect(Collectors.toList());
            this.saveBatch(customerList);
            return true;
        } catch (Exception e) {
            throw new ServiceException("导入-资源客户失败：" + e.getMessage());
        }
    }

    /**
     * 导出-资源客户
     * @param response 响应
     * @param customerQco 资源客户查询条件
     */
    @Override
    public void export(HttpServletResponse response, CustomerQco customerQco) {
        try {
            // 查询导出数据
            List<Customer> customers = this.pageList(customerQco);

            // 使用hutool工具导出数据，xlsx文件
            ExcelWriter writer = ExcelUtil.getWriter(true);
            // 自定义标题别名
            writer.addHeaderAlias("index", "序号");
            writer.addHeaderAlias("customerName", "客户名称");
            writer.addHeaderAlias("phone", "联系电话");
            writer.addHeaderAlias("sex", "性别");
            writer.addHeaderAlias("region", "所属区域");
            writer.addHeaderAlias("customerSource", "客户来源");
            writer.addHeaderAlias("assignStatus", "分配状态");
            writer.addHeaderAlias("createTime", "创建时间");

            List<Map<String, Object>> dataList = IntStream.range(0, customers.size())
                    .mapToObj(i -> {
                        Customer customer = customers.get(i);
                        Map<String, Object> rowMap = new HashMap<>();
                        rowMap.put("index", i + 1);
                        rowMap.put("customerName", customer.getCustomerName());
                        rowMap.put("phone", customer.getPhone());
                        rowMap.put("sex", customer.getSexMc());
                        rowMap.put("region", customer.getRegion());
                        rowMap.put("customerSource", customer.getCustomerSourceMc());
                        rowMap.put("assignStatus", customer.getAssignStatusMc());
                        rowMap.put("createTime", customer.getCreateTime());
                        return rowMap;
                    }).collect(Collectors.toList());
            writer.write(dataList, true);

            // 设置导出文件名，导出客户端下载
            String fileName = "资源客户数据" + System.currentTimeMillis() + ".xlsx";
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);

            // 关闭流
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            writer.close();
            IoUtil.close(out);
        } catch (Exception e) {
            throw new ServiceException("导出-资源客户失败！");
        }
    }

    /**
     * 修改-公共客户资源|我的客户管理
     * @param customer 资源客户信息
     * @return 资源客户信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Customer edit(Customer customer) {
        // 参数校验
        Assert.notNull(customer.getIntentionLevel(), "意向等级不能为空");
        Assert.notNull(customer.getContactStatus(), "联系方式状态不能为空");
        if (!ObjUtil.equals(ContactStatusEnum.NOTADDED.getCode(), customer.getContactStatus())) {
            Assert.notEmpty(customer.getContactAccount(), "工作账号不能为空");
        }
        // 根据Id获取数据库数据
        Customer customerInfo = Assert.notNull(this.getById(customer.getId()), "要修改的资源客户记录不存在");
        // 拷贝
        BeanUtils.copyNotEmptyProperties(customer, customerInfo);
        // 判断是否添加客户联系方式
        if (!ObjUtil.equals(ContactStatusEnum.NOTADDED.getCode(), customer.getContactStatus()) && ObjUtil.equals(AssignStatusEnum.UNASSIGN.getCode(), customerInfo.getAssignStatus())) {
            // 公共客户资源：未分配，添加客户联系方式, 存入客户资源分配日志表
            AllocationCustomerLog allocationCustomerLog = new AllocationCustomerLog();
            allocationCustomerLog.setGUID();
            allocationCustomerLog.setCustomerId(customerInfo.getId());
            allocationCustomerLog.setToUserId(SecurityUtils.getUserId());
            allocationCustomerLog.setAssignTime(new Date());
            allocationCustomerLog.setType(AssignTypeEnum.ASSIGN.getCode());
            allocationCustomerLogService.save(allocationCustomerLog);

            // 更改状态为已分配
            customerInfo.setAssignStatus(AssignStatusEnum.ASSIGNED.getCode());

            // 我的客户管理：从公共客户资源过来已分配；从资源客户自动分配过来的也已分配，就是没添加联系方式（定时任务扫描，三天没添加联系方式，再回到公共客户资源），添加联系方式（也是当前用户，分配记录也已存在）。
        }
        // 更新
        this.updateById(customerInfo);
        return customerInfo;
    }

    /**
     * 查询分配三天没加联系方式的资源客户Id集合
     * @return 资源客户id集合
     */
    @Override
    public List<String> selectDiff3DaysIdList() {
        return customerMapper.selectDiff3DaysIdList();
    }

    /**
     * 转移客户
     * @param transferCustomerDto 转移客户dto
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean transferCustomer(TransferCustomerDto transferCustomerDto) {
        // 虽然前端列表点击传来的数据是当前用户的，但是api调用传来的参数不一定是当前用户的，需要校验下选中的客户数据是否是当前用户的
        Long userId = SecurityUtils.getUserId();
        String username = SecurityUtils.getUsername();
        String customerId = transferCustomerDto.getCustomerId();
        // 校验要转移的客户记录是否存在
        Customer customerInfo = Assert.notNull(this.getById(customerId), "要转移的客户记录不存在");
        // 校验数据库数据是否添加联系方式
        if (ObjUtil.isNull(customerInfo.getContactStatus()) || ObjUtil.equals(ContactStatusEnum.NOTADDED.getCode(), customerInfo.getContactStatus())) {
            throw new ServiceException("该客户未添加联系方式，不能转移");
        }
        // 校验选中的客户数据是否是当前用户负责的
        Customer customer = customerMapper.getCustomerByIdAndUserId(customerId, userId);
        if (ObjUtil.isNull(customer)) {
            throw new ServiceException("您不是该客户的当前负责人，无权操作");
        }
        // 更新用户信息
        BeanUtils.copyNotEmptyProperties(transferCustomerDto, customerInfo);
        this.updateById(customerInfo);
        // 将客户转移给同事，记录日志
        Long toUserId = transferCustomerDto.getToUserId();
        AllocationCustomerLog allocationCustomerLog = new AllocationCustomerLog();
        allocationCustomerLog.setGUID();
        allocationCustomerLog.setCustomerId(customerId);
        allocationCustomerLog.setFromUserId(userId);
        allocationCustomerLog.setToUserId(toUserId);
        allocationCustomerLog.setAssignTime(new Date());
        allocationCustomerLog.setType(AssignTypeEnum.TRANSFER.getCode());
        allocationCustomerLogService.save(allocationCustomerLog);
        // websocket通知变更信息
        socketServer.pushMessage(String.valueOf(toUserId), socketServer.formatMessage(WebsocketConst.CUSTOM_TRANSFER, username + "将客户 " + customerInfo.getCustomerName() +" 转移给你了"));
        return true;
    }
}
